/*******************************************************************************
 * Homework 4: Wordsearch.cpp, CSCE 240, Spring 2010
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * Description: This class consists of a default constructor, two mutators, 
 * one for the class variable rowCount and one for colCount. The class also
 * has six functions initialize, findFirstLetter, search and display,readArray,
 * and readWords which are explained in detail in the function description.  
 * This function initialize is called in the main function with parameters for
 * the input and output streams. The various arrays are set up and initalized 
 * along with other variables needed for computation by the functions readArray
 * and readWords which are called by initialize(). The function readWords uses
 * a vector to hold the list of words and reads the words one by one and calls
 * the findFirstLetter function for each.  
 *
 * The findFirst letter function searches the array until it finds the first
 * letter of the word and then calls the search function several times, in 
 * order to search different directions, with different parameters like RIGHT
 * and ZERO which signifies search to the right(moving right along columns
 * and not moving along rows). The word, the position of the array the first
 * letter was found in, and the outFile are also passed to the search function.
 *
 * The search function searches in the direction specified in the parameters
 * (explained further in search function comments) by moving along that 
 * specified direction and when the end of the array is reached you wrap
 * around and continue searching. This is accomplished by modding by the
 * rowCount and colCount. Once one letter does not match the word the 
 * function returns false and if all letters match the function returns true.
 *
 * The display function is called in the findFirstLetter function only if 
 * the search function was successful and returns true. The display function
 * uses an array of the same size as the letters array but all indices 
 * contain the '*' character. When a word is found the array is overwritten 
 * with that word as it appears in the array. It needs the same parameters as  
 * the search function because it is essentially refinding the word the way it 
 * was found with search only it is displaying it in the array.  Also an 
 * outFile parameter is needed to write to a file. 
 *
 * Includes Wordsearch.h
*******************************************************************************/

#include "Wordsearch.h"


/*******************************************************************************
 * Default constructor for Wordsearch
*******************************************************************************/
Wordsearch::Wordsearch(){

}

/*******************************************************************************
 * Destructor for Wordsearch
*******************************************************************************/
Wordsearch::~Wordsearch(){

}

/*******************************************************************************
 * Mutator method for the class variable rowCount
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * Private method to set the class variable rowCount to the value specified
 * by the parameter rows. Called in initialize function.
 *
 * Parameters:
 * int rows - value to be assigned to rowCount
 *
 * Output: none
 *
 * Returns: none
*******************************************************************************/
void Wordsearch::setRowCount(int rows){
  rowCount = rows;
}
/*******************************************************************************
 * Mutator method for the class variable colCount
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * Private method to set the class variable colCount to the value specified
 * by the parameter cols. Called in initialize function.
 *
 * Parameters:
 * int cols - value to be assigned to colCount
 *
 * Output: none
 *
 * Returns: none
*******************************************************************************/
void Wordsearch::setColCount(int cols){
  colCount = cols;
}


/*******************************************************************************
 * Function to initialize the class variables and call private functions of
 * Wordsearch
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * First the number of rows and columns are read in from arrIn and set using
 * the mutator methods. Then the array of characters is read in using the  
 * function readArray. Next the display array which consists of only the '*'
 * character is set up using the function setDisplayArray. The original 
 * list of words is displayed to the outFile using the readWords function.
 * The search for words is called in the readWords function as well.
 *
 * No error checking is done in this function. Input and output streams are 
 * assumed to be opened in the main function.
 *
 * Parameters:
 * ifstream& arrIn- input file for the array of characters, passed by reference
 * ifstream& wordsIn- input file for the list of words, passed by reference
 * ofstream& outFile- output file, passed by reference
 *
 * Output: none expect for a log of what happens
 *
 * Returns: none
*******************************************************************************/
void Wordsearch::initialize(ifstream& arrIn, ifstream& wordsIn, 
                            ofstream& outFile){
  int rows;
  int cols;
     
  if( arrIn >> rows ){
    setRowCount(rows);
  }

  if( arrIn >> cols ){
    setColCount(cols);
  }
  
  readArray(arrIn, outFile);

  setDisplayArray();

  readWords(wordsIn, outFile);  
  
  
}
/*******************************************************************************
 * Function to read the matrix of characters from the input file and put it
 * into the array letters.
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * This function reads from the input file and puts the letter read from the
 * matrix at the appropriate index in the array letters. Then the array of 
 * letters is printed to the outFile stream. Called in the initialize function.
 *
 * No error checking is done in this function. Input and output streams are 
 * assumed to have been opened correctly in Main and rowCount and colCount
 * are assumed to have been set in initialize.
 *
 * Parameters:
 * ifstream& arrIn - input stream for the matrix of characters file
 * ofstream& outFile - output stream for the output file
 *
 * Output: none except for a log of what happens
 *
 * Returns: none
*******************************************************************************/
void Wordsearch::readArray(ifstream& arrIn, ofstream& outFile ){

  outFile << "The original array of characters is:\n";
  for(int i = 0; i < rowCount ; i++){

    for(int j = 0; j < colCount; j++){

      if( arrIn >> letters[i][j] ){
        outFile << letters[i][j] << " ";
      }

    }//for(int j = 0; j < colCount; j++)
    outFile << endl;
  }//for(int i = 0; i < rowCount ; i++)

  outFile << endl;

}

/*******************************************************************************
 * Function to read and print the words from the wordsearch list and also
 * read each word and call the findFirstLetter function for that word.
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * First the original list of words from the input file is echoed to the 
 * output file and that word is put into the vector wordsList. Then using an 
 * iterator the words are read from the vector and passed to the 
 * findFirstLetter function. If the findFirstLetter function returns false
 * the word was not found and a message is displayed to the output file.
 *
 * Parameters:
 * ifstream& wordsIn - input stream for the file containing the list of words
 * ofstream& outFile - output stream for the output file
 *
 * Output: none except for a log of what happens
 *
 * Returns: none
*******************************************************************************/
void Wordsearch::readWords(ifstream& wordsIn, ofstream& outFile){
  string s;
  string currentWord;
  vector<string> wordsList;
  vector<string>::iterator iter;
  
  outFile << "The original list of words to be searched for is:\n";
  while( wordsIn >> s ){
    wordsList.push_back(s);
    iter++;
    outFile << s << endl;
  }//while( wordsIn >> s )

  outFile << endl;
   
 
  outFile << "Output for successful searches is: \n\n";

  for(iter = wordsList.begin(); iter < wordsList.end() ; iter++){
    if(findFirstLetter(*iter, outFile)){
    }
    else{
      outFile << "word not Found: " << *iter << endl;
    }
  }//for(iter = wordsList.begin(); iter < wordsList.end() ; iter++)
 
}

/*******************************************************************************
 * Function to set up displayArr which consists of just the asterisk '*' 
 * character. Used to display word in display() function.
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * This function just sets every index of the array displayArr to have the 
 * value '*'. In the display function the word that is found is shown in 
 * this array with all other letters shown as '*'.
 *
 * Parameters: none
 *
 * Output: none
 *
 * Returns: none
*******************************************************************************/
void Wordsearch::setDisplayArray(){
  for(int i = 0; i < rowCount; i++){
    for(int j = 0; j < colCount; j++){
      displayArr[i][j] = '*';
    }//for(int j = 0; j < colCount; j++)
  }//for(int i = 0; i < rowCount; i++)
}



/*******************************************************************************
 * Function to search the array of characters for the first letter of a word
 * and call search function if that letter is found.
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 * 
 * The function uses a nested for loop to go through the array of characters
 * checking each index to see if it is equal to the first letter of the word
 * being searched. If it finds a index with a matching first letter than the 
 * search function is called 8 times to account for each direction being 
 * searched(parameters change depending on which direction your searching).
 * If one of the searches is successful than the display function is called
 * and the function returns true. This function returns false if the word is
 * not found. 
 *
 * No error checking is done. searchWord is assumed to not be null when it is
 * passed by the initialize function and outFile is assumed to be opened.
 *
 * Parameters:
 * string searchWord-word being searched
 * outFile- output file, passed by reference

*******************************************************************************/
bool Wordsearch::findFirstLetter(string searchWord, ofstream& outFile){
  for(int i = 0; i < rowCount; i++){
    for(int j = 0; j < colCount; j++){
      if( searchWord.at(0) == letters[i][j]){
       
        //searching to the right
        if( search(searchWord, RIGHT, ZERO, i, j)){
          display(searchWord, RIGHT, ZERO, i, j, outFile); 
          return true;
	//searching to the left
	}else if(search(searchWord, LEFT, ZERO, i, j)){
          display(searchWord, LEFT, ZERO, i, j, outFile);
          return true;
        //searching up
	}else if(search(searchWord, ZERO, UP , i, j)){
          display(searchWord, ZERO, UP, i, j, outFile);
	  return true;
	//searching down
	}else if(search(searchWord, ZERO, DOWN, i, j)){
          display(searchWord, ZERO, DOWN, i, j, outFile);
          return true;
	//searching northeast
        }else if(search(searchWord, RIGHT, UP,  i, j)){
          display(searchWord, RIGHT, UP, i, j, outFile);
	  return true;
	//searching southeast
	}else if(search(searchWord, RIGHT, DOWN, i, j)){
          display(searchWord, RIGHT, DOWN, i, j, outFile);
	  return true;
	//searching northwest
        }else if(search(searchWord, LEFT, UP , i, j)){
          display(searchWord, LEFT, UP, i, j, outFile);
	  return true;
	//searching southwest
	}else if(search(searchWord, LEFT, DOWN, i, j)){
          display(searchWord, LEFT, DOWN, i, j, outFile);
	  return true;
        }
      
        
      }
    }//for(int j = 0; j < colCount; j++)
  }//for(int i = 0; i < rowCount; i++)
  return false;
}//bool Wordsearch::findFirstLetter(string searchWord, ofstream& outFile)


       
/*******************************************************************************
 * Function to search for a word in a specified direction once the first letter
 * of the word has been found.
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * A for loop is run from 1(since we already found first letter) to the length
 * of the word(not inclusive). An if statement checks to see if the character
 * at the index of the 'next position' is the same as the next position of the
 * word.
 *
 * The row index of the 'next position' is calculated by adding the 
 * parameter rowInc(which can be {1,-1,0} or in other words 
 * {down,up,no change}) and the total number of rows to the current row 
 * and mod by the total number of rows. Note: adding rowCount when modding by
 * rowCount is essentially adding 0 but prevents the complications of modding
 * by negative numbers.(rowCount=0(mod rowCount))
 *
 * The column index of the 'next position' is calculated in a similar fashion.
 * Instead of adding the parameter rowInc, colInc is added(which can be 
 * {1,-1,0} or in other words {right,left,no change}.
 *
 * If the letter at the index of the next position of the array matches that
 * of the word then rowInc and colInc are added to the current row and current
 * column respectively. Once a letter is found that does not match the 
 * function returns false. If all letters are found then the function returns  
 * true because the search was successful.
 *
 * Parameters:
 * string searchWord - word being searched
 * int colInc - column increment, value used to change the position of the
 *              column depending on the direction be searched, passed to 
 *              findFirstLetter and is a class enumerated value
 * int rowInc - row increment, value used to change the position of the row
 * int currentRow - index of the row the first letter was found
 * int currentCol - index of the column the first letter was found
 *
 * Output: none
 *
 * Returns: true - if search was successful
 *          false - if search was not successful
 *
*******************************************************************************/
bool Wordsearch::search(string searchWord, int colInc, int rowInc,
                        int currentRow, int currentCol){
  
  
  for(int i = 1; i < searchWord.length() ; i++){

    //if searchWord.at(i) == character at next position
    if(searchWord.at(i) == letters[(currentRow + rowInc + rowCount)
                                                        % rowCount]
                           [(currentCol + colInc + colCount) % colCount]){
      //increments row and col depending on rowInc and colInc
      currentRow +=  rowInc;
      currentCol +=  colInc;
    }
    else{
      break;
    }
    //word found
    if( i == searchWord.length() - 1){
      return true;
    }
  }
  return false;

}//bool Wordsearch::search

/*******************************************************************************
 * Function to display the word found in an array where all other characters
 * besides the letters of the word are '*'
 * Author: Andrew Shore
 * Date Last Modified: 1 March 2010
 *
 * The first letter of the word is placed in the index at which it was found
 * outside of the for loop. Then the for loop is ran from 1(first letter taken
 * care of) to searchWord.length()(not inclusive) and each letter of the word
 * is placed at its proper index. The index is determined in the same way as 
 * it was in the search function using the parameter increments and modding by
 * the number of Rows or Columns.  The parameters are the same as that of the
 * successful search function with the addition of the output stream outFile.
 *
 * After the word has been placed in the array of asterisks a nested for loop
 * is run to display each index of the display array. After the index is
 * displayed it is overwritten with an asterisk so that the same array can be 
 * used for other words. All this information is sent to the outFile output 
 * stream.
 *
 * No error checking is done in this function. All parameters are assumed to 
 * be correct.
 *
 * Parameters:
 * string searchWord - word being searched for
 * int colInc - value used to change the position of the column with respect 
 *              to what direction the word was found(see search function
 *              description if confused)
 * int rowInc - value used to change the position of the row with respect to 
 *              what direction the word was found
 * ofstream& outFile - output file, passed by reference
*******************************************************************************/
void Wordsearch::display(string searchWord, int colInc, int rowInc, 
                         int currentRow, int currentCol,ofstream& outFile){
  //sets first letter of word outside of for loop
  displayArr[currentRow][currentCol] = searchWord.at(0);
  
  //starts at i = 1 since we've taken care of first letter
  for(int i = 1; i < searchWord.length() ; i++){

    displayArr[((currentRow + rowInc + rowCount) % rowCount)]
              [((currentCol + colInc + colCount) % colCount)] 
              = searchWord.at(i);

    currentRow += rowInc;
    currentCol += colInc;

  }//for(int i = 1; i < searchWord.length() ; i++)
  outFile << "word in array is\n";

  for(int i = 0; i < rowCount; i++){
    for(int j = 0; j < colCount; j++){
      outFile << displayArr[i][j] << " ";
      //resets the displayArr after being output so it can be reused
      displayArr[i][j] = '*';
    }//for(int j = 0; j < colCount; j++)

    outFile << endl;
  }//for(int i = 0; i < rowCount; i++)

  outFile << endl;

}//void Wordsearch::display
  




